Previous Book Contents Book Index Next

Inside Macintosh: Overview /
Chapter 9 - Processes


Handling Errors

Occasionally, a system software routine might be unable to perform the service you've requested of it. You might, for instance, pass GetResource a resource specification that doesn't apply to any resource in any of the open resource files. Or, the user might have opened so many document windows that there simply isn't enough space in your application's heap to open another one. In these situations, you need to determine that an error has occurred and react to it in some appropriate manner.

The system software has several ways of informing your application that a requested service is not possible. Many functions return a result code that indicates whether the function completed successfully, and if not, what the reason for failure was. These functions return a result of type OSErr. Here's an example:

myResult := FindFolder(kOnSystemDisk, kPreferencesFolderType,
                         kDontCreateFolder, myVRefNum, myDirID);
IF myResult = noErr THEN
   ...
ELSE
   ...;
Other routines--mainly procedures and functions that return other types of results--don't return a result code directly. To find out whether these kinds of routines were successful, you need to call an additional system software routine. For example, some Resource Manager procedures don't directly indicate if the resource operation was successful or not. To find that out, you can call the ResError function. The DoSavePrefs routine (defined in Listing 3-6 on page 66) uses this strategy to update a preferences resource:

RmveResource(myHandle);
IF ResError = noErr THEN
   AddResource(myPrefData, kPrefResType, kPrefResID, myName);
IF ResError = noErr THEN
   WriteResource(myPrefData);
Similarly, the Resource Manager routine Get1Resource returns a handle to the specified resource data. If for some reason the resource cannot be opened, the function returns a handle whose value is NIL. You can inspect the returned value to determine whether it's safe to proceed.

myHandle := Get1Resource(kPrefResType, kPrefResID);
IF myHandle <> NIL THEN
   ...;
You could also call ResError to determine if Get1Resource succeeded. In other words, the following lines are equivalent to the preceding ones:

myHandle := Get1Resource(kPrefResType, kPrefResID);
IF ResError <> noErr THEN
   ...;
The Memory Manager provides the MemError function, which works much as ResError does. For Memory Manager functions that return a value, you can either inspect the returned value or call MemError to determine if the function completed successfully.

This book has used a fairly simple strategy for detecting and reacting to the normal kinds of problems. When calling a function that returns a pointer or handle, Venn Diagrammer checks that the value of that pointer or handle isn't NIL. If it is NIL, Venn Diagrammer usually just skips any code that uses that pointer or handle.

IMPORTANT
Venn Diagrammer's error-handling strategy is far too simple for most applications, and it runs afoul of good human interface principles. For example, if the DoCreateWindow function (defined in Listing 6-6 on page 117) cannot allocate the memory it needs, it exits and returns a NIL window pointer to the calling routine. The net result is that no new window is created, in spite of the user's desire to create one. At the very least, DoCreateWindow should inform the user that a new window could not be created because sufficient memory was not available.
Occasionally, an application might run into some more serious problem during its execution that renders further processing impossible or undesirable. For example, if the Venn Diagrammer application isn't able to allocate enough memory for the data structure it uses to maintain information about a document window's geometry, there's no point in continuing to run, because the application won't be able to draw anything in any document windows. In that case, the application should gracefully terminate its own execution. (See Listing 5-3 on page 95.)

To do this, the Venn Diagrammer application defines the DoBadError procedure and calls it whenever there is a problem serious enough to warrant such drastic action. The DoBadError procedure is defined in Listing 9-5.

Listing 9-5 Handling serious errors

PROCEDURE DoBadError (myError: Integer);
VAR
   myItem:     Integer;
   myMessage:  Str255;
BEGIN
   SetCursor(arrow);                         {set arrow cursor}
   GetIndString(myMessage, kErrorStrings, myError);
   ParamText(myMessage, '', '', '');
   myItem := Alert(rErrorAlert, NIL);        {display message}
   ExitToShell;                              {terminate execution}
END;
The application passes DoBadError an index into a resource of type 'STR#' that contains messages indicating the types of serious errors. First DoBadError sets the cursor to the standard arrow cursor (this step is necessary only if your application ever changes the cursor). Then DoBadError retrieves the appropriate message from the application's resource fork and calls the Dialog Manager routine ParamText to substitute the message into the alert box text. After that, DoBadError displays the alert box by calling the Dialog Manager routine Alert. (See Figure 7-2 on page 134 for an example of this alert box.) Finally, DoBadError calls the Process Manager procedure ExitToShell to terminate the application immediately.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
9 JUL 1996